<template>
    <view>
        {{ renderTime }}
    </view>
</template>
<script setup>
import { computed, watch, reactive, onBeforeMount } from 'vue';
const emit = defineEmits(['input', 'on-end', 'on-restart', 'on-paused', 'update:modelValue']);
const props = defineProps({
    paused: {
        default: false,
        type: Boolean
    },

    /** 时间格式 */
    format: {
        type: String,
        default: 'HH:mm:ss'
    },
    /** 开始时间 */
    startTime: {
        type: [Number, String],
        validator(v) {
            const dateStr = new Date(v).toString().toLowerCase();
            return dateStr !== 'invalid date';
        }
    },
    /** 结束时间 */
    endTime: {
        type: [Number, String],
        validator(v) {
            const dateStr = new Date(v).toString().toLowerCase();
            return dateStr !== 'invalid date';
        }
    },
    /** 是否开启毫秒 */
    millisecond: {
        default: false,
        type: Boolean
    },
    autoStart: {
        type: Boolean,
        default: true
    },
    /** 倒计时时长，单位毫秒 */
    time: {
        type: [Number, String],
        default: 0
    }
});

const state = reactive({
    restTime: 0, // 倒计时剩余时间时间
    timer: null,
    counting: !props.paused && props.autoStart, // 是否处于倒计时中
    handleEndTime: Date.now(), // 最终截止时间
    diffTime: 0 // 设置了 startTime 时，与 date.now() 的差异
});

const padZero = (num, length = 2) => {
    num += '';
    while (num.length < length) {
        num = '0' + num;
    }
    return num.toString();
};
const getTimeStamp = timeStr => {
    if (!timeStr) return Date.now();
    let t = timeStr;
    // eslint-disable-next-line no-useless-escape
    t = t > 0 ? +t : t.toString().replace(/\-/g, '/');
    return new Date(t).getTime();
};

const renderTime = computed(() => {
    return formatRemainTime(state.restTime);
});

// 倒计时 interval
const initTime = () => {
    state.handleEndTime = getTimeStamp(props.endTime);
    state.diffTime = Date.now() - getTimeStamp(props.startTime); // 时间差
    if (!state.counting) state.counting = true;
    tick();
};

const tick = () => {
    // state.timer = setInterval(
    //     () => {
    //         if (state.counting) {
    //             const currentTime = Date.now() - state.diffTime;
    //             const remainTime = Math.max(state.handleEndTime - currentTime, 0);

    //             state.restTime = remainTime;
    //             if (!remainTime) {
    //                 state.counting = false;
    //                 pause();
    //                 emit('on-end');
    //             }

    //             if (remainTime > 0) {
    //                 tick();
    //             }
    //         }
    //     },
    //     props.millisecond ? 1 : 1000
    // );
    if (state.counting) {
        const currentTime = Date.now() - state.diffTime;
        const remainTime = Math.max(state.handleEndTime - currentTime, 0);

        state.restTime = remainTime;
        if (!remainTime) {
            state.counting = false;
            pause();
            emit('on-end');
        }

        if (remainTime > 0) {
            setTimeout(() => {
                tick();
            }, 1000);
        }
    }
};

// 将倒计时剩余时间格式化   参数： t  时间戳  type custom 自定义类型
const formatRemainTime = (t, type) => {
    const ts = t;
    let rest = {
        d: 0,
        h: 0,
        m: 0,
        s: 0,
        ms: 0
    };

    const SECOND = 1000;
    const MINUTE = 60 * SECOND;
    const HOUR = 60 * MINUTE;
    const DAY = 24 * HOUR;

    if (ts > 0) {
        rest.d = ts >= SECOND ? Math.floor(ts / DAY) : 0;
        rest.h = Math.floor((ts % DAY) / HOUR);
        rest.m = Math.floor((ts % HOUR) / MINUTE);
        rest.s = Math.floor((ts % MINUTE) / SECOND);
        rest.ms = Math.floor(ts % SECOND);
    }

    return type == 'custom' ? rest : parseFormat({ ...rest });
};

const parseFormat = time => {
    let { d, h, m, s, ms } = time;
    let format = props.format;

    if (format.includes('DD')) {
        format = format.replace('DD', padZero(d));
    } else {
        h += Number(d) * 24;
    }

    if (format.includes('HH')) {
        format = format.replace('HH', padZero(h));
    } else {
        m += Number(h) * 60;
    }

    if (format.includes('mm')) {
        format = format.replace('mm', padZero(m));
    } else {
        s += Number(m) * 60;
    }

    if (format.includes('ss')) {
        format = format.replace('ss', padZero(s));
    } else {
        ms += Number(s) * 1000;
    }

    if (format.includes('S')) {
        const msC = padZero(ms, 3).toString();

        if (format.includes('SSS')) {
            format = format.replace('SSS', msC);
        } else if (format.includes('SS')) {
            format = format.replace('SS', msC.slice(0, 2));
        } else if (format.includes('S')) {
            format = format.replace('SS', msC.slice(0, 1));
        }
    }
    return format;
};

// 开始
const start = () => {
    if (!state.counting && !props.autoStart) {
        state.counting = true;
        state.handleEndTime = Date.now() + Number(state.restTime);
        tick();
        emit('on-restart', state.restTime);
    }
};
// 暂定
const pause = () => {
    // cancelAnimationFrame(state.timer);
    clearInterval(state.timer);
    state.counting = false;
    emit('on-paused', state.restTime);
};

//重置
const reset = () => {
    if (!props.autoStart) {
        pause();
        state.restTime = props.time;
    }
};

onBeforeMount(() => {
    if (props.autoStart) {
        initTime();
    } else {
        state.restTime = props.time;
    }
});

watch(
    () => state.restTime,
    value => {
        let tranTime = formatRemainTime(value, 'custom');
        emit('update:modelValue', tranTime);
        emit('input', tranTime);
    }
);

watch(
    () => props.paused,
    (v, ov) => {
        if (!ov) {
            if (state.counting) {
                pause();
            }
        } else {
            if (!state.counting) {
                state.counting = true;
                state.handleEndTime = Date.now() + Number(state.restTime);
                tick();
            }
            emit('on-restart', state.restTime);
        }
    }
);

watch(
    () => props.endTime,
    value => {
        initTime();
    }
);

watch(
    () => props.startTime,
    value => {
        initTime();
    }
);
</script>
<style lang="scss"></style>
